from pymysql import Connection
from model_data.Employee import Employee


class view_logic:
    def __init__(self):
        self.conn = Connection(
            host='localhost',
            port=3306,
            user='root',
            password='12345678',
            autocommit=True,
        )
        self.cur1 = self.conn.cursor()
        self.conn.select_db('employee_data')

        # 新增GUI模式标识
        self.gui_mode = False


    def set_gui_mode(self, mode=True):
        """设置GUI模式（用于控制输出方式）"""
        self.gui_mode = mode

    def emp_input(self):
        """
        这个算是最终版本。
        首先，对于输入提示进行了更详细的描述。前一个版本只能适用于知晓数据库中字段类型的人使用。
        现版本将python中的提示与表中的字段相对应，并作出相应提示，是否必填通过键require的赋值实现

        其次，旧版本是挨个字段使用input给变量赋值，太麻烦，现在改用列表字典，容易维护，而且调用也方便.

        然后在验证的部分，我一开始尝试挨个去验证，太繁琐，且并非所有的字段都需要特别处理，非空判断可以把字段统一化分到必填选项，在这里进行非空判断

        然后又改为了通过分类输入的数据，来进行不同的操作，字符串类型没有需要什么特别操作的；整数类型，只有工资和年龄我做了相应的处理
        整数部分，进行提示后，为了不让用户输入类型错误的数据，我进行了显式的数据类型转换，目标类型就是当前field["type"]的value
        这样做，如果输入数字但非整数，那也可以转换成整数，如果非数字，那么就会报错，从而停止该条数据进入数据库

        并且，我已经知道了会出现的错误类型，所以可以主动抛出异常 raise，并给出相应的提示
        :return:
        """

        FIELDS_CONFIG = [
            {"prompt": "工号（必填）:", "key": "employee_id", "type": str, "required": True},
            {"prompt": "姓名（必填）:", "key": "name", "type": str, "required": True},
            {"prompt": "年龄（数字）:", "key": "age", "type": int, "required": True},
            {"prompt": "性别（男/女）:", "key": "gender", "type": str, "required": True},
            {"prompt": "学历（如：本科）:", "key": "education", "type": str, "required": True},
            {"prompt": "工资（数字）:", "key": "salary", "type": int, "required": True},
            {"prompt": "地址（选填）:", "key": "address", "type": str, "required": False},
            {"prompt": "电话（选填）:", "key": "phone_number", "type": str, "required": False}
        ]

        emp_data = {}
        print("请输入职工信息（带*为必填项）")


        for field in FIELDS_CONFIG:
            while True:

                required_mark = "*" if field.get("required", True) else ""  #对必填项提示
                user_input = input(f"{field['prompt']} {required_mark}").strip()  #key后边一个*，电话和住址没有*


                if not user_input and field.get("required", True):
                    print("警告 此字段为必填项，请重新输入")
                    continue

                try:

                    if field["type"] == int:
                        if not user_input:
                            raise ValueError("不能为空")
                        value = field["type"](user_input)

                        if field["key"] == "age" and not (1 <= value <= 65):
                            raise ValueError("年龄需在1-65之间")
                        if field["key"] == "salary" and value < 0:
                            raise ValueError("工资不能为负数")
                    else:
                        value = user_input

                    emp_data[field["key"]] = value
                    break

                except ValueError as e:
                    print(f"错误 输入无效：{str(e)}，请重新输入")

        eRecord1 = Employee(
            emp_data['employee_id'],
            emp_data['name'],
            emp_data['age'],
            emp_data['gender'],
            emp_data['education'],
            emp_data['salary'],
            emp_data.get('address', ''),  #设了个默认值，就实现了可选
            emp_data.get('phone_number', '')
        )


        try:
            sql = """INSERT INTO employee
                     (employee_id, name, age, gender, education, salary, address, phone)
                     VALUES (%s, %s, %s, %s, %s, %s, %s, %s)"""

            data = (
                eRecord1.id,
                eRecord1.name,
                eRecord1.age,
                eRecord1.gender,
                eRecord1.education,
                eRecord1.salary,
                eRecord1.address,
                eRecord1.phone_number
            )

            self.cur1.execute(sql, data)
            print(" 职工信息添加成功！")

        # 但是对于异常捕获的部分，我没有去细分异常的类型。AI给出的建议是在生产中需要细分异常类型

        except Exception as e:
            print(f"错误 数据库操作失败：{str(e)}")

    def emp_Browse(self) -> tuple:
        """
        实现浏览全部信息
        执行一个查询所有语句，然后返回结果，而且会自动按照id正序输出
        :return:
        """
        self.cur1.execute("""select * from employee""")
        # 元组类型，employee_id, name, age, gender, education, salary, address, phone
        Inquire_result = self.cur1.fetchall()
        for result in Inquire_result:
            print(result)

    def emp_select(self):
        """
        使用二分之类的算法太麻烦，不如就用索引进行查找，因此我的思路是优化数据库的层面，建个索引更简单
        :return:
        """
        print("选择您的查询方式：\n 1.按工资查询  \n 2.按学历查询")
        num = int(input("请输入："))

        if num == 1:
            try:
                lower = int(input("请输入目标工资下限："))
                upper = int(input("请输入目标工资上限："))
                # 确保下限不大于上限，不用判断谁大，就排序就行更方便
                lower, upper = sorted([lower, upper])

                self.cur1.execute("""
                    SELECT * FROM employee 
                    WHERE salary BETWEEN %s AND %s
                    ORDER BY salary  -- 确保有序返回
                """, (lower, upper))

                for row in self.cur1.fetchall():
                    print(row)

            except ValueError:
                print("输入错误：工资必须为数字")    #做一个简单的验证

        elif num == 2:
            target_edu = input("请输入目标学历：").strip()
            self.cur1.execute("""
                SELECT * FROM employee 
                WHERE education = %s
            """, (target_edu,))

            for row in self.cur1.fetchall():
                print(row)

    def emp_order(self):
        """
        排序
        :return:
        """
        self.cur1.execute("""SELECT * FROM employee ORDER BY employee_id;""")
        sort_result = self.cur1.fetchall()
        for result in sort_result:
            print(result)

    def emp_delete(self):
        delete_id = input("请输入您需要删除的职工id：")
        delete_result = self.cur1.execute("""DELETE FROM employee WHERE employee_id=%s"""
                                          ,delete_id)  # 返回一个数字类型，意义为成功影响的行数
        if delete_result > 0:
            print("删除成功")
        else:
            print("删除失败")

    def emp_update(self):
        """
        优化后的职工信息修改功能，使用字典存储职工信息，这点与插入信息相同，字典相对于列表更方便
        获取职工ID，查询当前信息，输入并验证新信息，执行更新操作，处理事务，以及显示结果。
        :return:
        """
        try:
            """
            获取要修改的职工ID
            并且验证是否为数字类型，并且使用死循环，可以无限获取，直到能够获取正确的id
            """
            while True:
                try:
                    modify_id = int(input("请输入您需要修改的职工ID："))
                    break
                except ValueError:
                    print("错误：ID必须为数字，请重新输入！")

            # 查询当前信息,参数化查询,这里使用fetchone就行，我查到这样做会提高解包效率
            self.cur1.execute("SELECT * FROM employee WHERE employee_id = %s", (modify_id,))
            current_data = self.cur1.fetchone()

            if not current_data:
                print("错误：未找到该ID的职工信息！")
                return   #如果未找到id，那么就会返回到Main_View中调用emp_update的地方

            print("\n当前职工信息：")
            self._print_employee_info(current_data)

            # 输入新信息（带验证）
            new_info = self._get_validated_employee_info(modify_id)

            # 执行更新操作
            with self.conn.cursor() as cur:  # 假设使用事务管理
                sql = """
                    UPDATE employee
                    SET 
                        employee_id = %s,
                        name = %s,
                        age = %s,
                        gender = %s,
                        education = %s,
                        salary = %s,
                        address = %s,
                        phone = %s
                    WHERE employee_id = %s  # 始终使用原始ID进行匹配
                """
                cur.execute(sql, (
                    new_info['employee_id'],
                    new_info['name'],
                    new_info['age'],
                    new_info['gender'],
                    new_info['education'],
                    new_info['salary'],
                    new_info['address'],
                    new_info['phone'],
                    modify_id  # 使用原始ID作为WHERE条件
                ))

                if cur.rowcount == 0:
                    print("修改失败：未找到匹配的记录")
                    return

                self.conn.commit()  # 提交事务
                print("修改成功！")

                # 显示更新后的信息
                cur.execute("SELECT * FROM employee WHERE employee_id = %s", (new_info['employee_id'],))
                self._print_employee_info(cur.fetchone())

        except Exception as e:
            self.conn.rollback()  # 发生错误时回滚
            print(f"操作失败：{str(e)}")

    def _get_validated_employee_info(self, original_id):
        """
        信息修改的内部方法：获取并验证用户输入
        :param original_id:
        :return:
        """
        # 首先对对于字段进行初始化定义，列表字典类型
        fields = [
            {"prompt": "工号", "key": "employee_id", "type": str, "required": True},
            {"prompt": "姓名", "key": "name", "type": str, "required": True},
            {"prompt": "年龄", "key": "age", "type": int, "required": True},
            {"prompt": "性别", "key": "gender", "type": str, "required": True},
            {"prompt": "学历", "key": "education", "type": str, "required": True},
            {"prompt": "工资", "key": "salary", "type": int, "required": True},
            {"prompt": "地址", "key": "address", "type": str, "required": True},
            {"prompt": "电话", "key": "phone", "type": str, "required": True}
        ]

        new_info = {}
        for field in fields:
            while True:
                value = input(f"{field['prompt']}：") #无限循环输入，直到都正确输入，提示语是字段中prompt的值
                if not value and field['required']:  #禁止空值输入
                    print("错误：此字段必填！")
                    continue

                try:
                    """这两处都是基础用法，只是在赋值或者参数的地方，组合了其他地方的数据"""
                    if field['type'] == int:
                        value = field['type'](value)   #这里做了个类型转换，因为在库中定义的字段类型是有差异的，这也是为什么使用字典来作为新数据的数据容器。动态的判断该转化成什么类型
                        # 特殊验证：年龄范围
                        if field['key'] == 'age' and not (1 <= value <= 70):
                            raise ValueError("年龄必须在1-70之间")
                        # 特殊验证：工资范围
                        if field['key'] == 'salary' and value < 0:
                            raise ValueError("工资不能为负数")
                    new_info[field['key']] = value   #在这里，将新的数据存储到另一个字典中。new_info字典的键是fields列表字典的 "key": "employee_id"。值为获取到的value
                    break
                except ValueError as ve:
                    print(f"输入无效：{ve}，请重新输入{field['prompt']}：")

        # 额外验证：如果修改了ID，检查新ID是否已存在
        if new_info['employee_id'] != original_id:
            #参数化查询
            self.cur1.execute(
                "SELECT COUNT(*) FROM employee WHERE employee_id = %s",
                (new_info['employee_id'],)
            )
            if self.cur1.fetchone()[0] > 0:
                raise ValueError("该工号已存在，请使用其他工号！")

        return new_info  #返回给emp_update使用

    def _print_employee_info(self, data):
        """
        信息修改的信息修改的内部方法：格式化打印职工信息"
        :param data: 
        :return: 
        """""
        if not data:
            print("无相关数据")
            return

        print("\n" + "-" * 50)
        print(f"工号：{data[0]}")
        print(f"姓名：{data[1]}")
        print(f"年龄：{data[2]}")
        print(f"性别：{data[3]}")
        print(f"学历：{data[4]}")
        print(f"工资：{data[5]}")
        print(f"地址：{data[6]}")
        print(f"电话：{data[7]}")
        print("-" * 50 + "\n")
